package com.ljx.observerMode;

import java.util.ArrayList;
import java.util.List;

/**
 * 观察者模式
 * 观察者模式定义了一个一对多的依赖关系，使得当被观察者状态发生改变时，与之相依赖的所有观察者对象都能得到通知并自动更新
 *
 * 使用场景：
 * 跨系统的消息交换场景。
 * 关联行为的场景。
 *
 * 优点：
 * 观察者只需等待主题通知，无需了解主题相关的细节；同时主题只负责通知观察者，无需了解观察者如何处理通知。实现了观察者和被观察者（耦合的双方）依赖于抽象耦合。
 * 观察者增加或删除无需修改主题的代码，只需调用主题对应的增加或者删除的方法即可。增强了程序的可维护性和可拓展性。
 * 缺点：
 * 主题持有观察者的引用，如果从主题中删除观察者时未正常处理，会导致观察者无法被回收。
 * 消息的通知顺序执行，如果一个观察者卡顿，会影响整体的执行效率，若遇到这种情况，一般会采用异步实现。
 *
 * 经典案例：
 * spring的发布订阅就是基于同步的观察者模式: 简单来说就是将所有的监听者注册到一个列表里面，然后当发布事件时，通过循环监听者列表，
 * 在循环里面调用每个监听者的onEvent方法，每个监听者实现的在onEvent方法里面判断传入的event是否属于当前需要的event，属于就处理该事件，反之不处理
 * ApplicationEventMulticaster就是示例讲的观察者顶层接口
 * ApplicationListener就是示例代码的监听者顶层接口
 *
 * nacos中有很多地方都使用到了观察者模式，如client端和server端建立连接，发布连接事件，相关监听者做相应的处理，断开连接也是一样
 * 在server端接收到client端的注册请求后，会发布一个注册事件的通知
 *
 * @作者 LJX
 * @日期 2022/12/21 15:44
 */
public class ObserverTest {

    public static void main(String[] args) {
        Task1 task1 = new Task1();
        Task2 task2 = new Task2();

        ObservationTarget ot = new ObservationTarget();
        ot.addObserver(task1);
        ot.addObserver(task2);

        ot.noticeAll("通知了");

    }

}

/**
 * 被观察对象
 */
class ObservationTarget{
    //观察者容器
    private List<Observer> observerList = new ArrayList<>();

    //添加观察者
    public void addObserver(Observer ob){
        observerList.add(ob);
    }

    //移除观察者
    public void removeObserver(Observer ob){
        observerList.remove(ob);
    }

    //通知方法
    public void noticeAll(String data){
        for (Observer observer : observerList) {
            observer.update(data);
        }
    }

}

/**
 * 观察者接口
 */
interface Observer{

    void update(String data);

}

/**
 * 观察任务1
 */
class Task1 implements Observer{

    @Override
    public void update(String data) {
        System.out.println("观察任务1的方法：" + data);
    }
}

/**
 * 观察任务2
 */
class Task2 implements Observer{

    @Override
    public void update(String data) {
        System.out.println("观察任务2的方法：" + data);
    }
}
